package com.cloud.wms.ui.sort.presenter;


import android.text.TextUtils;

import com.annimon.stream.Stream;
import com.cloud.core.base.BaseRxPresenter;
import com.cloud.core.http.error.ApiException;
import com.cloud.core.utils.MessageCreator;
import com.cloud.wms.app.FineExApplication;
import com.cloud.wms.entity.ContainerEntity;
import com.cloud.wms.entity.Page;
import com.cloud.wms.http.Params;
import com.cloud.wms.http.observer.LoadingObserver;
import com.cloud.wms.http.observer.ResponseWrapper;
import com.cloud.wms.tools.PageHelper;
import com.cloud.wms.tools.RxUtils;
import com.cloud.wms.tools.TaskHelper;
import com.cloud.wms.ui.main.entity.CommodityEntity;
import com.cloud.wms.ui.main.entity.RemoteEntity;
import com.cloud.wms.ui.main.entity.TaskEntity;
import com.cloud.wms.ui.main.entity.UserEntity;
import com.cloud.wms.ui.sort.contract.OrderSortContract;
import com.cloud.wms.ui.sort.entity.BatchInfoEntity;
import com.cloud.wms.ui.sort.entity.BindInfoEntity;
import com.cloud.wms.ui.sort.entity.OrderEnum;
import com.cloud.wms.ui.sort.entity.SortCommodityEntity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;

import javax.inject.Inject;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;


/**
 * @Author:Chen
 * @Date: 2021-01-14 15:51
 * @Description: 清点
 */
public class OrderSortPresenter extends BaseRxPresenter<OrderSortContract.View> implements OrderSortContract.Presenter {
    public static final int BATCH_LIST = 0x100;

    public static final int BIND_CONTAINER = 0x101;

    public static final int SORT_COMMODITY = 0x102;

    public static final int SUBMIT_SORT = 0x103;

    public static final int SORT_DETAIL = 0x104;

    public static final int CHECK_BIND_CONTAINER = 0x105;

    public static final int NEXT_TASK = 0x106;

    public static final int NO_NEXT_TASK = 0x110;

    public static final int SORT_COMPLETE = 0x107;

    public static final int TASK = 0x108;

    public static final int SORT_POS_DETAIL = 0x109;

    @Inject
    public OrderSortPresenter() {

    }

    /**
     * 检测波次是否绑定容器信息
     *
     * @param billId
     */
    @Override
    public void checkBindContainer(long billId) {
        Params params = new Params();
        params.put("BillType", OrderEnum.Order);
        params.put("BillID", billId);
        params.put("IsGetOrderInfo", false);

        FineExApplication
                .component()
                .http()
                .sortCheckBind(params)
                .map(new ResponseWrapper<>())
                .flatMap((Function<ArrayList<BindInfoEntity>, ObservableSource<ArrayList<BindInfoEntity>>>) bindInfoEntities -> {
                    if (bindInfoEntities == null || bindInfoEntities.size() == 0) {
                        return Observable.error(new ApiException("当前波次订单绑定信息查询失败！"));
                    }
                    return Observable.just(bindInfoEntities);
                })
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<ArrayList<BindInfoEntity>>(mView.provideContext()) {
                    @Override
                    public void onSuccess(ArrayList<BindInfoEntity> info) {
                        mView.showContent();
                        mView.onSuccess(MessageCreator.createMessage(info, CHECK_BIND_CONTAINER));
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                        mView.showError();
                    }
                });
    }

    /**
     * 加载波次列表数据
     *
     * @param batchCode
     */
    @Override
    public void loadBatchList(String batchCode, int page) {
        Params params = Params.newInstance(Params.Type.MEMBER);
        if (!TextUtils.isEmpty(batchCode)) {
            params.put("BatchCode", batchCode);
        }
        params.put("Sorting", "createDate");
        params.put("SkipCount", PageHelper.skipCount(page));
        params.put("MaxResultCount", PageHelper.PAGE_SIZE);
        params.put("BatchTypeID", 1);////1.散单分拣，2.单sku分拣，3.笼车分拣，4.团购分拣
        FineExApplication
                .component()
                .http()
                .sortBatchList(params)
                .map(new ResponseWrapper<>())
                .map(Page::getItems)
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<ArrayList<BatchInfoEntity>>(mView.provideContext()) {
                    @Override
                    public void onSuccess(ArrayList<BatchInfoEntity> info) {
                        if (page == 0) {
                            mView.onSuccess(MessageCreator.createMessage(info, PageHelper.LIST_NEW_DATA));
                        } else {
                            mView.onSuccess(MessageCreator.createMessage(info, PageHelper.LIST_NEXT_DATA));
                        }
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                    }
                });
    }

    @Override
    public void receiveTask(long billId, String taskCode) {
        Params paramsReceived = Params.newInstance(Params.Type.MEMBER);
        paramsReceived.put("BatchID", billId);
        paramsReceived.put("TaskCode", taskCode);

        FineExApplication
                .component()
                .http()
                .sortReceivedOrderId(paramsReceived)
                .map(new ResponseWrapper<>())
                .flatMap((Function<ArrayList<TaskEntity>, ObservableSource<Long>>) tasks -> {
                    IdentityHashMap<String, Object> paramsNoReceive = new IdentityHashMap<>();
                    paramsNoReceive.put("BatchID", billId);
                    ArrayList<Long> orderIds = new ArrayList<>();
                    if (tasks != null && !tasks.isEmpty()) {
                        for (int i = 0; i < tasks.size(); i++) {
                            orderIds.add(tasks.get(i).getBillID());
                        }
                    }
                    paramsNoReceive.put("lisOrderID", orderIds);
                    return FineExApplication
                            .component()
                            .http()
                            .sortNoReceiveOrderId(paramsNoReceive)
                            .map(new ResponseWrapper<>())
                            .flatMap((Function<ArrayList<Long>, ObservableSource<Long>>) longs1 -> {
                                if (longs1 == null || longs1.isEmpty()) {
                                    return Observable.error(new ApiException("当前波次没有可执行的订单！"));
                                }
                                return Observable.just(longs1.get(0));
                            });
                })
                .flatMap((Function<Long, ObservableSource<TaskEntity>>) aLong ->
                        TaskHelper.orderTaskList(billId, taskCode)
                                .map(taskEntity -> {
                                    taskEntity.setBillID(aLong);
                                    taskEntity.setMainBillID(billId);
                                    return taskEntity;
                                }))
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskID", taskEntity.getTaskID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ProductCategory", userInfo.getProductCategory());
                    params.put("ExecutorID", userInfo.getUserID());
                    return TaskHelper.receiveTask(params)
                            .map(aVoid -> {
                                taskEntity.setMainWorkID(aVoid);
                                return taskEntity;
                            });
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskID", taskEntity.getTaskID());
                    params.put("OrderID", taskEntity.getBillID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ProductCategory", userInfo.getProductCategory());
                    params.put("ExecutorID", userInfo.getUserID());
                    return TaskHelper.receiveOrderTask(params)
                            .map(aVoid -> {
                                taskEntity.setWorkID(aVoid);
                                return taskEntity;
                            });
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("workId", taskEntity.getWorkID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("executerId", userInfo.getUserID());
                    return TaskHelper.executeTask(params)
                            .map(aVoid -> taskEntity);
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskCode", taskEntity.getTaskCode());
                    params.put("BatchID", billId);
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ExecutorID", userInfo.getUserID());
                    return FineExApplication
                            .component()
                            .http()
                            .userOrderTask(params)
                            .map(new ResponseWrapper<>())
                            .map(aVoid -> {
                                taskEntity.setMainWorkID(taskEntity.getMainWorkID());
                                return taskEntity;
                            });
                })
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<TaskEntity>(mView.provideContext()) {
                    @Override
                    public void onSuccess(TaskEntity info) {
                        mView.onSuccess(MessageCreator.createMessage(info, TASK));
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                    }
                });
    }

    @Override
    public void acceptNextTask(long billId, String taskCode) {
        Params paramsReceived = Params.newInstance(Params.Type.MEMBER);
        paramsReceived.put("BatchID", billId);
        paramsReceived.put("TaskCode", taskCode);

        FineExApplication
                .component()
                .http()
                .sortReceivedOrderId(paramsReceived)
                .map(new ResponseWrapper<>())
                .flatMap((Function<ArrayList<TaskEntity>, ObservableSource<Long>>) tasks -> {
                    IdentityHashMap<String, Object> paramsNoReceive = new IdentityHashMap<>();
                    paramsNoReceive.put("BatchID", billId);
                    ArrayList<Long> orderIds = new ArrayList<>();
                    if (tasks != null && !tasks.isEmpty()) {
                        for (int i = 0; i < tasks.size(); i++) {
                            orderIds.add(tasks.get(i).getBillID());
                        }
                    }
                    paramsNoReceive.put("lisOrderID", orderIds);
                    return FineExApplication
                            .component()
                            .http()
                            .sortNoReceiveOrderId(paramsNoReceive)
                            .map(new ResponseWrapper<>())
                            .flatMap((Function<ArrayList<Long>, ObservableSource<Long>>) longs1 -> {
                                if (longs1 == null || longs1.isEmpty()) {
                                    return Observable.error(new ApiException("当前波次任务已完成，请切换波次领用任务！"));
                                }
                                return Observable.just(longs1.get(0));
                            });
                })
                .flatMap((Function<Long, ObservableSource<TaskEntity>>) aLong ->
                        TaskHelper.orderTaskList(billId, taskCode, "当前波次任务已完成，请切换波次领用任务！")
                                .map(taskEntity -> {
                                    taskEntity.setBillID(aLong);
                                    taskEntity.setMainBillID(billId);
                                    return taskEntity;
                                }))
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskID", taskEntity.getTaskID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ProductCategory", userInfo.getProductCategory());
                    params.put("ExecutorID", userInfo.getUserID());
                    return TaskHelper.receiveTask(params)
                            .map(aVoid -> {
                                taskEntity.setMainWorkID(aVoid);
                                return taskEntity;
                            });
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskID", taskEntity.getTaskID());
                    params.put("OrderID", taskEntity.getBillID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ProductCategory", userInfo.getProductCategory());
                    params.put("ExecutorID", userInfo.getUserID());
                    return TaskHelper.receiveOrderTask(params)
                            .map(aVoid -> {
                                taskEntity.setWorkID(aVoid);
                                return taskEntity;
                            });
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("workId", taskEntity.getWorkID());
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("executerId", userInfo.getUserID());
                    return TaskHelper.executeTask(params)
                            .map(aVoid -> taskEntity);
                })
                .flatMap((Function<TaskEntity, ObservableSource<TaskEntity>>) taskEntity -> {
                    Params params = new Params();
                    params.put("TaskCode", taskEntity.getTaskCode());
                    params.put("BatchID", billId);
                    UserEntity userInfo = FineExApplication.component().loginCache().getUserInfo();
                    params.put("JobStationID", userInfo.getJobStationID());
                    params.put("ExecutorID", userInfo.getUserID());
                    return FineExApplication
                            .component()
                            .http()
                            .userOrderTask(params)
                            .map(new ResponseWrapper<>())
                            .map(aVoid -> {
                                taskEntity.setMainWorkID(taskEntity.getMainWorkID());
                                return taskEntity;
                            });
                })
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<TaskEntity>(mView.provideContext()) {
                    @Override
                    public void onSuccess(TaskEntity info) {
                        mView.onSuccess(MessageCreator.createMessage(info, NEXT_TASK));
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                        if (msg.contains("波次任务已完成"))
                            mView.onSuccess(MessageCreator.createMessage(null, NO_NEXT_TASK));
                    }
                });
    }

    /**
     * 检查容器并绑定容器
     *
     * @param billId
     * @param containerCode
     */
    @Override
    public void bindContainer(long billId, String containerCode) {
        Params params = Params.newInstance(Params.Type.WAREHOUSE);
        params.put("BoxCode", containerCode);
        FineExApplication
                .component()
                .http()
                .checkContainerUseState(params)
                .map(new ResponseWrapper<>())
                .flatMap((Function<ContainerEntity, ObservableSource<ContainerEntity>>) containerEntity -> {
                    ArrayList<HashMap<String, Object>> list = new ArrayList<>();
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("containerID", containerEntity.getContainerID());
                    map.put("orderID", billId);
                    list.add(map);
                    Params params1 = Params.newInstance(Params.Type.WAREHOUSE);
                    params1.put("orderType", 2);
                    params1.put("lstBox", list);
                    params1.put("userID", FineExApplication.component().loginCache().getUserInfo().getUserID());
                    return FineExApplication
                            .component()
                            .http()
                            .sortBindContainer(params1)
                            .map(new ResponseWrapper<>())
                            .flatMap((Function<Boolean, ObservableSource<ContainerEntity>>) aBoolean -> {
                                if (!aBoolean)
                                    return Observable.error(new ApiException("绑定失败，请检查数据！"));
                                return Observable.just(containerEntity);
                            });
                })
                .map(containerEntity -> {
                    BindInfoEntity entity = new BindInfoEntity();
                    entity.setBillID(billId);
                    entity.setContainerCode(containerEntity.getContainerCode());
                    entity.setContainerID(containerEntity.getContainerID());
                    return entity;
                })
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<BindInfoEntity>(mView.provideContext()) {
                    @Override
                    public void onSuccess(BindInfoEntity info) {
                        mView.onSuccess(MessageCreator.createMessage(info, BIND_CONTAINER));
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                    }
                });
    }

    @Override
    public void loadSortCommodity(long billId, long orderId) {
        Params params = new Params();
        params.put("BatchID", billId);
        ArrayList<Long> longs = new ArrayList<>();
        longs.add(orderId);
        params.put("lisOrderID", orderId);
        //1 边检边分-多笼车  2先拣后分-单笼车（东西拣到一起，需要二次分拨） 3单SKU分拣  4按订单分拣
        params.put("SortingType", 4);

        FineExApplication
                .component()
                .http()
                .sortBatchOrderDetail(params)
                .map(new ResponseWrapper<>())
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<ArrayList<SortCommodityEntity>>(mView.provideContext()) {
                    @Override
                    public void onSuccess(ArrayList<SortCommodityEntity> info) {
                        List<SortCommodityEntity> entities = Stream.ofNullable(info)
                                .sortBy(SortCommodityEntity::getPosCode)
                                .sortBy(sortCommodityEntity -> sortCommodityEntity.getNeedAmount() <= 0 ? 1 : -1)
                                .toList();

                        ArrayList<SortCommodityEntity> commodityBeans = new ArrayList<>();
                        for (int i = 0; i < entities.size(); i++) {
                            SortCommodityEntity commodityEntity = entities.get(i);
                            commodityEntity.setFlag(commodityEntity.getNeedAmount() <= 0);
                            if (commodityEntity.getNeedAmount() > 0) {
                                commodityBeans.add(commodityEntity);
                                for (int j = i + 1; j < entities.size(); j++) {
                                    if (commodityEntity.getPosID() == entities.get(j).getPosID() && entities.get(j).getNeedAmount() > 0) {
                                        commodityBeans.add(entities.get(j));
                                    }
                                }
                                break;
                            }
                        }
                        if (commodityBeans.isEmpty()) {
                            mView.onSuccess(MessageCreator.createMessage(commodityBeans, SORT_COMPLETE));
                        } else {
                            mView.onSuccess(MessageCreator.createMessage(commodityBeans, SORT_COMMODITY));
                        }
                        mView.onSuccess(MessageCreator.createMessage(getBatchPos(entities), SORT_POS_DETAIL));
                        mView.showContent();
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                        mView.showError();
                    }
                });
    }


    public List<SortCommodityEntity> getBatchPos(List<SortCommodityEntity> entities) {
        for (int i = 0; i < entities.size(); i++) {
            SortCommodityEntity entity = entities.get(i);
            entity.setFlag(entity.getNeedAmount() <= 0);
        }
        ArrayList<SortCommodityEntity> list = new ArrayList<>();
        Stream.ofNullable(entities)
                .groupBy(SortCommodityEntity::getPosCode)
                .forEach(entry -> {
                    SortCommodityEntity entity = new SortCommodityEntity();
                    entity.setPosCode(entry.getKey());
                    entity.setFlag(true);
                    List<SortCommodityEntity> value = entry.getValue();
                    for (int i = 0; i < value.size(); i++) {
                        SortCommodityEntity commodityEntity = value.get(i);
                        entity.setPosID(commodityEntity.getPosID());
                        entity.setBarCode(commodityEntity.getBarCode());
                        entity.setCommodityId(commodityEntity.getCommodityId());
                        if (!commodityEntity.isFlag()) {
                            entity.setFlag(false);
                        }
                    }
                    list.add(entity);
                });
        return Stream.ofNullable(list)
                .sortBy(SortCommodityEntity::getPosCode)
                .sorted((o1, o2) -> {
                    boolean o1Flag = o1.isFlag();
                    boolean o2Flag = o2.isFlag();
                    return Boolean.compare(o1Flag, o2Flag);
                })
                .toList();
    }

    /**
     * 加载波次已分拣，未分拣商品数据
     *
     * @param billId
     * @param state
     */
    @Override
    public void loadSortDetail(long billId, long orderId, boolean state) {
        Params params = new Params();
        params.put("BatchID", billId);
        ArrayList<Long> longs = new ArrayList<>();
        longs.add(orderId);
        params.put("lisOrderID", orderId);
        //1 边检边分-多笼车  2先拣后分-单笼车（东西拣到一起，需要二次分拨） 3单SKU分拣  4按订单分拣
        params.put("SortingType", 4);

        FineExApplication
                .component()
                .http()
                .sortBatchOrderDetail(params)
                .map(new ResponseWrapper<>())
                .flatMap((Function<ArrayList<SortCommodityEntity>, ObservableSource<SortCommodityEntity>>) Observable::fromIterable)
                .filter(carSortDetachEntity -> {
                    if (state) {
                        return carSortDetachEntity.getNeedAmount() <= 0;
                    } else {
                        return carSortDetachEntity.getNeedAmount() > 0;
                    }
                })
                .toList()
                .toObservable()
                .compose(mView.toLifecycle())
                .compose(RxUtils.threadSwitch())
                .subscribe(new LoadingObserver<List<SortCommodityEntity>>(mView.provideContext()) {
                    @Override
                    public void onSuccess(List<SortCommodityEntity> info) {
                        if (info == null || info.isEmpty()) {
                            mView.showEmpty();
                        } else {
                            mView.showContent();
                            mView.onSuccess(MessageCreator.createMessage(info, SORT_DETAIL));
                        }
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                        mView.showError();
                    }
                });
    }

    /**
     * 订单分拣-确认分拣下架
     *
     * @param commodityEntity
     * @param containerId
     * @param amount
     */
    @Override
    public void submitSort(TaskEntity taskEntity, CommodityEntity commodityEntity, String containerId, int amount) {
        ArrayList<Params> list = new ArrayList<>();
        Params params = Params.newInstance(Params.Type.MEMBER);
        params.put("sortingType", 4);//1 边检边分-多笼车  2先拣后分-单笼车（东西拣到一起，需要二次分拨） 3单SKU分拣  4按订单分拣
        params.put("batchID", taskEntity.getMainBillID());
        params.put("orderID", taskEntity.getBillID());
        params.put("posID", commodityEntity.getPosID());
        params.put("commodityID", commodityEntity.getCommodityId());
        params.put("stockType", commodityEntity.getStockType());
        params.put("productBatchID", commodityEntity.getProductBatchID());
        params.put("sortAmount", amount);
        List<String> containerList = new ArrayList<>();
        containerList.add(containerId);
        params.put("containerID", containerList);
        params.put("userID", FineExApplication.component().loginCache().getUserInfo().getUserID());
        list.add(params);

        Params taskParams = new Params();
        taskParams.put("oSDownShelves", list);
        taskParams.put("workID", taskEntity.getWorkID());
        taskParams.put("taskWorkID", taskEntity.getMainWorkID());
        taskParams.put("productCategory", taskEntity.getProductCategory());
        taskParams.put("jobStationID", taskEntity.getJobStationID());
        taskParams.put("appKey", taskEntity.getAppKey());

        FineExApplication
                .component()
                .http()
                .sortTaskBatchConfirm(taskParams)
                .map(new ResponseWrapper<>())
                .compose(RxUtils.threadSwitch())
                .compose(mView.toLifecycle())
                .subscribe(new LoadingObserver<Object>(mView.provideContext()) {
                    @Override
                    public void onSuccess(Object info) {
                        mView.onSuccess(MessageCreator.createMessage(info, SUBMIT_SORT));
                    }

                    @Override
                    public void onError(String msg) {
                        mView.error(msg);
                    }
                });
    }
}
